;(function($){
	
$.fn.appendTemplate = function(template, data){
	$(this).doInsert("append", template, data);
};
	
$.fn.beforeTemplate = function(template, data){
	$(this).doInsert("before", template, data);
};

$.fn.afterTemplate = function(template, data){
	$(this).doInsert("after", template, data);
};

$.fn.doInsert = function(type, template, data){
	var tpl;

	if(template instanceof $.template){
		tpl = template;
	}else{
		tpl = new $.template(template)
	}
	
	if(!tpl.compiled){
		tpl.compile();
	}

	var result = tpl.applyTemplate(data);

	return this.each(
		function(){ $(this)[type](result); }
	);
}

//nocompile: 创建时不进行编译，如此参数不存在，则会进行编译
$.template = function(html, nocompile){
	var a = arguments;
    if($.utils.isArray(html)){
        html = html.join("");
    }else if(a.length > 1){
        var buf = [];
        for(var i = 0, len = a.length; i < len; i++){
            if(typeof a[i] == 'object'){
                $.extend(this, a[i]);
            }else{
                buf[buf.length] = a[i];
            }
        }
        html = buf.join('');
    }
    /**@private*/
    this.html = html;
    //如果已经编译过了，那么需要重新编译
    if(this.compiled || !nocompile){
        this.compile();   
    }
};

$.template.prototype = {
	/**
     * Returns an HTML fragment of this template with the specified values applied.
     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
     * @return {String} The HTML fragment
     */
    applyTemplate : function(values){
        if(this.compiled){
            return this.compiled(values);
        }
        var tpl = this;
        var fn = function(m, name, format, args){
            return values[name] !== undefined ? values[name] : "";
        };
        return this.html.replace(this.re, fn);
    },
    
    /**
     * Sets the HTML used as the template and optionally compiles it.
     * @param {String} html
     * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
     * @return {$.Template} this
     */
    set : function(html, compile){
        this.html = html;
        this.compiled = null;
        if(compile){
            this.compile();
        }
        return this;
    },
    
    /**
    * The regular expression used to match template variables 
    * @type RegExp
    * @property 
    */
    re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
    
    /**
     * Compiles the template into an internal function, eliminating the RegEx overhead.
     * @return {$.Template} this
     */
    compile : function(){
    	var sep = $.browser.mozilla ? "+" : ",";
        var fn = function(m, name, format, args){
            args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
            return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
        };
        var body;
        // branched to use + in gecko and [].join() in others
        if($.browser.mozilla){
            body = "this.compiled = function(values){ return '" +
                   this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
                    "';};";
        }else{
            body = ["this.compiled = function(values){ return ['"];
            body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
            body.push("'].join('');};");
            body = body.join('');
        }
        eval(body);
        return this;
    }
}

})(jQuery);